package com.yuantu.judiciary.exception;

import com.yuantu.judiciary.common.Response;
import com.yuantu.judiciary.common.ResponseFactory;
import com.yuantu.judiciary.common.SysCode;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;


/**
 * 全局异常处理器
 *
 * @author syw
 * @since 2023-06-07
 **/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private static final String METHOD_ARGUMENT_NOT_VALID_MESSAGE = "Method Argument Not Valid";

    @ExceptionHandler(ServiceException.class)
    public Response<?> businessExceptionHandler(ServiceException e) {
        log.error("ServiceException", e);
        return ResponseFactory.errResponse(e);
    }

    @ExceptionHandler(RuntimeException.class)
    public Response<?> runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        return ResponseFactory.errResponse(SysCode.SYSTEM_ERROR.getCode(), "系统错误");
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public Response<?> jsonErrorHandler(ConstraintViolationException e) {
        return ResponseFactory.errResponse(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        StringBuilder errMessage = new StringBuilder();

        for (FieldError error : ex.getBindingResult().getFieldErrors()) {
            errMessage.append(error.getField()).append(": ").append(error.getDefaultMessage()).append(System.lineSeparator());
        }
        for (ObjectError error : ex.getBindingResult().getGlobalErrors()) {
            errMessage.append(error.getObjectName()).append(": ").append(error.getDefaultMessage()).append(System.lineSeparator());
        }

        String finalErrMessage = errMessage.length() == 0 ? METHOD_ARGUMENT_NOT_VALID_MESSAGE : errMessage.toString();
        return super.handleExceptionInternal(ex, ResponseFactory.errResponse(status.value(), finalErrMessage), headers, status, request);
    }

    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return super.handleExceptionInternal(ex, ResponseFactory.errResponse(status.value(), ex.getMessage()), headers, status, request);
    }

    @Override
    protected ResponseEntity<Object> handleMissingPathVariable(MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return super.handleExceptionInternal(ex, ResponseFactory.errResponse(status.value(), ex.getMessage()), headers, status, request);
    }

    @Override
    protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return super.handleExceptionInternal(ex, ResponseFactory.errResponse(status.value(), ex.getMessage()), headers, status, request);
    }

}
